package top.broncho.anpods

import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.os.Build
import android.os.IBinder
import android.view.View
import android.widget.RemoteViews
import androidx.core.app.NotificationCompat
import androidx.lifecycle.LifecycleService
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
import org.jetbrains.anko.AnkoLogger
import org.jetbrains.anko.info
import org.jetbrains.anko.warn
import top.broncho.anpods.model.BatteryState
import top.broncho.anpods.model.ConnectionState
import top.broncho.anpods.ui.widget.AnPodsDialog
import top.broncho.anpods.util.*
import java.text.SimpleDateFormat
import java.util.*

const val NOTIFICATION_ID = 9083150
const val CHANNEL_ID = "Anpods"
const val ACTION_POPUP = "${BuildConfig.APPLICATION_ID}.ACTION_POPUP"


class AnPodsService : LifecycleService(), AnkoLogger, CoroutineScope by MainScope() {
    private val simpleDateFormat by lazy { SimpleDateFormat("HH:mm", Locale.US) }
    private val anPodsDialog by lazy { AnPodsDialog(App.context) }

    private val notifyManager: NotificationManager by lazy {
        getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
    }

    override fun onBind(intent: Intent): IBinder {
        super.onBind(intent)
        throw UnsupportedOperationException("AnPodsService do not support bind!")
    }

    override fun onCreate() {
        super.onCreate()
        info("AnPodsService onCreate...")
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { //on oreo and newer, create a notification channel
            val channel =
                NotificationChannel(
                    CHANNEL_ID,
                    CHANNEL_ID,
                    NotificationManager.IMPORTANCE_HIGH
                ).apply {
                    enableVibration(false)
                    enableLights(false)
                    setShowBadge(true)
                    lockscreenVisibility = Notification.VISIBILITY_PUBLIC
                }
            notifyManager.createNotificationChannel(channel)
        }

        val pendingIntent = PendingIntent.getService(
            applicationContext,
            0,
            Intent(applicationContext, AnPodsService::class.java).apply { action = ACTION_POPUP },
            PendingIntent.FLAG_UPDATE_CURRENT
        )
        val notification = NotificationCompat.Builder(this, CHANNEL_ID).apply {
            setOngoing(true)
            priority = NotificationCompat.PRIORITY_MAX
            setSmallIcon(R.drawable.ic_airpods)
            setContentIntent(pendingIntent)
        }

        checkConnection()

        info { "register device change E" }
        fromBroadCast().onEach {
            airPodsConnectionState.value = it
            if (it.isConnected) {
                anPodsDialog.show()
            } else {
                anPodsDialog.onBackPressed()
            }
        }.launchIn(lifecycleScope)
        info { "register device change x" }

        airPodsConnectionState.observe({ lifecycle }) {
            connectionJob?.cancel()
            anPodsDialog.updateConnectedDevice(it)
            updateWidgetUI(notification)
            if (it.isConnected) {
                detectBattery()
            }
        }
        airPodsBatteryState.observe({ lifecycle }) {
            val state = airPodsConnectionState.value
            if (state == null || !state.isConnected) return@observe
            updateWidgetUI(notification)
            anPodsDialog.updateUI(it)
        }
    }

    private var detectJob: Job? = null
    private var connectionJob: Job? = null

    private fun checkConnection() {
        connectionJob = lifecycleScope.launch {
            val state = getConnected()
            info { "connection state = $state" }
            if (state.isConnected) {
                airPodsConnectionState.value = state
            }
        }
    }

    private fun detectBattery() {
        if (detectJob?.isActive == true) {
            info("detectAirPods! but it is still working")
            return
        }
        detectJob?.cancel()
        detectJob = batteryState().map {
            it.parse(getStr("key_model", "auto"))
        }.catch {
            warn { "detectBattery: onError=${it.message}" }
        }.onEach {
            info { "detectBattery: result=$it" }
            airPodsBatteryState.value = it
        }.onStart {
            info { "detectBattery: onStart..." }
        }.onCompletion {
            info { "detectBattery: onCompletion..." }
        }.launchIn(lifecycleScope)
    }

    private fun updateWidgetUI(
        notification: NotificationCompat.Builder,
        //views: RemoteViews,
        connectionState: ConnectionState? = airPodsConnectionState.value,
        batteryState: BatteryState? = airPodsBatteryState.value
    ) {
        if (connectionState == null || !connectionState.isConnected) {
            notification.setContentTitle("未连接")
            notification.setContentText("L: -  R: -  Case: -")
            notifyManager.notify(NOTIFICATION_ID, notification.build().apply {
                `when` = System.currentTimeMillis()
            })
            notifyManager.cancelAll()
            return
        }
        batteryState ?: return
        info { "updateNotification...." }
        notification.setContentTitle(connectionState.deviceName)
        val content =
            if (batteryState.caseBattery <= 10) "L:${
                getTitle(
                    batteryState.leftBattery,
                    batteryState.isLeftCharge
                )
            }  R:${
                getTitle(
                    batteryState.rightBattery, batteryState.isLeftCharge
                )
            }  Case:${getTitle(batteryState.caseBattery, batteryState.isLeftCharge)}"
            else "L:${getTitle(batteryState.leftBattery, batteryState.isLeftCharge)}  R:${
                getTitle(
                    batteryState.rightBattery, batteryState.isLeftCharge
                )
            }"
        notification.setContentText(content)
        notifyManager.notify(NOTIFICATION_ID, notification.build().apply {
            `when` = System.currentTimeMillis()
        })
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        info { "onStartCommand: flags=$flags" }
        if (intent?.action == ACTION_POPUP) {
            anPodsDialog.show()
            checkConnection()
        }
        return super.onStartCommand(intent, flags, startId)
    }

    override fun onDestroy() {
        super.onDestroy()
        info("onDestroy...")
    }
}
